//
//  clb_image.m
//  DeferredLighting
//
//  Created by Holmes Futrell on 2/10/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "clb_image.h"
#import "clb_error.h"

const char *clb_mem_flags_to_string(cl_mem_flags flags) {

	switch (flags) {
		case CL_MEM_COPY_HOST_PTR: return "CL_MEM_COPY_HOST_PTR";
		case CL_MEM_ALLOC_HOST_PTR: return "CL_MEM_ALLOC_HOST_PTR";
		case CL_MEM_USE_HOST_PTR: return "CL_MEM_USE_HOST_PTR";
		case CL_MEM_READ_ONLY: return "CL_MEM_READ_ONLY";
		case CL_MEM_WRITE_ONLY: return "CL_MEM_WRITE_ONLY";
		case CL_MEM_READ_WRITE: return "CL_MEM_READ_WRITE";
		default: return "unknown cl_mem_flags flag";
	}
	
}

const char *clb_channel_order_to_string(cl_channel_order order) {
/*
		 CL_R, or CL_A
		 CL_INTENSITY.  This format can only be used if channel data type = 
		 CL_UNORM_INT8, CL_UNORM_INT16, CL_SNORM_INT8, CL_SNORM_INT16, 
		 CL_HALF_FLOAT or CL_FLOAT.
		 CL_LUMINANCE.  This format can only be used if channel data type = 
		 CL_UNORM_INT8, CL_UNORM_INT16, CL_SNORM_INT8, CL_SNORM_INT16, 
		 CL_HALF_FLOAT or CL_FLOAT.
		 CL_RG, or CL_RA
		 CL_RGB.  This format can only be used if channel data type = 
		 CL_UNORM_SHORT_565, CL_UNORM_SHORT_555 or CL_UNORM_INT_101010.
		 CL_RGBA
		 CL_ARGB, CL_BGRA.  This format can only be used if channel data type =
		 CL_UNORM_INT8, CL_SNORM_INT8, CL_SIGNED_INT8 or CL_UNSIGNED_INT
		 }
 */
	switch(order) {
		case CL_R: return "CL_R";
		case CL_A: return "CL_A";
		case CL_INTENSITY: return "CL_INTENSITY";
		case CL_LUMINANCE: return "CL_LUMINANCE";
		case CL_RG: return "CL_RG";
		case CL_RA: return "CL_RA";
		case CL_RGB: return "CL_RGB";
		case CL_RGBA: return "CL_RGBA";
		case CL_ARGB: return "CL_ARGB";
		case CL_BGRA: return "CL_BGRA";
		default: return "unknown cl_channel_order order";
	}
	
}

const char *clb_channel_type_to_string(cl_channel_type type) {
	/*
	 CL_SNORM_INT8 Each channel component is a normalized signed 8-bit 
	 integer value
	 CL_SNORM_INT16 Each channel component is a normalized signed 16-bit 
	 integer value
	 CL_UNORM_INT8 Each channel component is a normalized unsigned 8-bit 
	 integer value
	 CL_UNORM_INT16 Each channel component is a normalized unsigned 16-
	 bit integer value
	 CL_UNORM_SHORT_565 Represents a normalized 5-6-5 3-channel RGB image.  
	 The channel order must be CL_RGB.
	 CL_UNORM_SHORT_555 Represents a normalized x-5-5-5 4-channel xRGB
	 image.  The channel order must be CL_RGB.
	 CL_UNORM_INT_101010 Represents a normalized x-10-10-10 4-channel xRGB
	 image. The channel order must be CL_RGB.
	 CL_SIGNED_INT8 Each channel component is an unnormalized signed 8-
	 bit integer value
	 CL_SIGNED_INT16 Each channel component is an unnormalized signed 16-
	 bit integer value
	 CL_SIGNED_INT32 Each channel component is an unnormalized signed 32-
	 bit integer value
	 CL_UNSIGNED_INT8 Each channel component is an unnormalized unsigned 
	 8-bit integer value
	 CL_UNSIGNED_INT16 Each channel component is an unnormalized unsigned 
	 16-bit integer value
	 CL_UNSIGNED_INT32 Each channel component is an unnormalized unsigned 
	 32-bit integer value
	 CL_HALF_FLOAT Each channel component is a 16-bit half-float value
	 CL_FLOAT Each channel component is a single precision floatingpoint value
*/	 
	switch(type) {
		case CL_SNORM_INT8: return "CL_SNORM_INT8";
		case CL_SNORM_INT16: return "CL_SNORM_INT16";
		case CL_UNORM_INT8: return "CL_UNORM_INT8";
		case CL_UNORM_INT16: return "CL_UNORM_INT16";
		case CL_UNORM_SHORT_565: return "CL_UNORM_SHORT_565";
		case CL_UNORM_SHORT_555: return "CL_UNORM_SHORT_555";
		case CL_UNORM_INT_101010: return "CL_UNORM_INT_101010";
		case CL_SIGNED_INT8: return "CL_SIGNED_INT8";
		case CL_SIGNED_INT16: return "CL_SIGNED_INT16";
		case CL_SIGNED_INT32: return "CL_SIGNED_INT32";
		case CL_UNSIGNED_INT8: return "CL_UNSIGNED_INT8";
		case CL_UNSIGNED_INT16: return "CL_UNSIGNED_INT16";
		case CL_UNSIGNED_INT32: return "CL_UNSIGNED_INT32";
		case CL_HALF_FLOAT: return "CL_HALF_FLOAT";
		case CL_FLOAT: return "CL_FLOAT";
		default: return "unknown cl_channel_type type";
	}
	
}



void clb_print_image_format_description(cl_image_format format) {

	printf("%s, \t%s\n", clb_channel_order_to_string(format.image_channel_order), clb_channel_type_to_string(format.image_channel_data_type));
	
}

const char * clb_image_info_to_string(cl_image_info param_name) {
	
	switch(param_name) {
		case CL_IMAGE_FORMAT: return "CL_IMAGE_FORMAT";
		case CL_IMAGE_ELEMENT_SIZE: return "CL_IMAGE_ELEMENT_SIZE";
		case CL_IMAGE_ROW_PITCH: return "CL_IMAGE_ROW_PITCH";
		case CL_IMAGE_SLICE_PITCH: return "CL_IMAGE_SLICE_PITCH";
		case CL_IMAGE_WIDTH: return "CL_IMAGE_WIDTH";
		case CL_IMAGE_HEIGHT: return "CL_IMAGE_HEIGHT";
		case CL_IMAGE_DEPTH: return "CL_IMAGE_DEPTH";
		default: return "Unknown image format info";
	}
	
}
	
void clb_print_image_description(cl_mem image) {

	printf("Image format:\n");

	CL_IMAGE_FORMAT;
	CL_IMAGE_ELEMENT_SIZE;
	CL_IMAGE_ROW_PITCH;
	CL_IMAGE_SLICE_PITCH;
	CL_IMAGE_WIDTH;
	CL_IMAGE_HEIGHT;
	CL_IMAGE_DEPTH;
	
	cl_image_format imageFormat;
	size_t elementSize, rowPitch, slicePitch, width, height, depth;
	
	clb_check_error_simple(clGetImageInfo(image, CL_IMAGE_FORMAT, sizeof(imageFormat), &imageFormat, NULL));
	clb_check_error_simple(clGetImageInfo(image, CL_IMAGE_ELEMENT_SIZE, sizeof(elementSize), &elementSize, NULL));
	clb_check_error_simple(clGetImageInfo(image, CL_IMAGE_ROW_PITCH, sizeof(rowPitch), &rowPitch, NULL));
	clb_check_error_simple(clGetImageInfo(image, CL_IMAGE_SLICE_PITCH, sizeof(slicePitch), &slicePitch, NULL));
	clb_check_error_simple(clGetImageInfo(image, CL_IMAGE_WIDTH, sizeof(width), &width, NULL));
	clb_check_error_simple(clGetImageInfo(image, CL_IMAGE_HEIGHT, sizeof(height), &height, NULL));
	clb_check_error_simple(clGetImageInfo(image, CL_IMAGE_DEPTH, sizeof(depth), &depth, NULL));

	clb_print_image_format_description(imageFormat);
	printf("element size = %d\n", (int)elementSize);
	printf("row pitch = %d\n", (int)rowPitch);
	printf("slice pitch = %d\n", (int)slicePitch);
	printf("width = %d\n", (int)width);
	printf("height = %d\n", (int)height);
	printf("depth = %d\n", (int)depth);

}

void clb_print_supported_2D_image_formats(cl_context context, cl_mem_flags flags) {

	cl_uint num_entries = 1024;
	cl_uint num_supported_formats = -1;
	cl_image_format image_formats[num_entries];
	
	int err = clGetSupportedImageFormats(context, flags, CL_MEM_OBJECT_IMAGE2D, num_entries, image_formats, &num_supported_formats);
	clb_check_error(err, "clGetSupportedImageFormats");
	
	printf("supported image formats for mode: %s\n", clb_mem_flags_to_string(flags));
	printf("channel order, channel type\n");

	int i;
	for (i=0; i<num_supported_formats; i++) {
		clb_print_image_format_description(image_formats[i]);
	}
	printf("--------------------------\n\n");

	
}